package com.pajk.user.service.credit;

import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.annotation.Resource;

import com.pajk.user.exception.CreditErrorEnum;
import com.pajk.user.service.common.http.HttpsChannel;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;

import com.pajk.user.exception.CreditServiceException;

/**
 * User: haihua.chenhh
 * Date: 14-3-20
 * Time: 下午12:45
 */
public class CreditServiceWlt {
    private static final Logger log                         = LoggerFactory
                                                                .getLogger(CreditServiceWlt.class);
    private static final String SIEBEL_MESSAGE_XPATH        = "/LPMS_Pionts/Request/PropertySet/SiebelMessage";
    private static final String MEMBERID_XPATH              = "/LPMS_Pionts/Request/PropertySet/SiebelMessage/MemberID";
    private static final String ADD_RESPONSE_DATA_XPATH     = "/response/data";
    private static final String CREATE_TEMP_ACCOUNT         = "/response/data";
    private static final String QUERY_RESPONSE_DATA_XPATH   = "/PropertySet/SiebelMessage";
    private static final String CONSUME_RESPONSE_DATA_XPATH = "/PropertySet/SiebelMessage";
    
    
    @Resource
    HttpsChannel wltHttpsChannel;

    private Document            queryCreditDoc;
    private Document            addCreditDoc;
    private Document            consumeCreditDoc;
    private Document            cancelConsumeCreditDoc;
    private Document            queryConsumeCreditDoc;
    private Document            createTempAccountDoc;
    
    private String              queryUrl;
    private String              addUrl;
    private String              consumeUrl;
    private String              cancelConsumeUrl;
    private String              queryConsumeUrl;
    private String              createTempAccountUrl;
    
    public void init() {
        SAXReader reader = new SAXReader();
        ClassPathResource addCreditXml = new ClassPathResource("META-INF/wlt/addCredit.xml");
        ClassPathResource queryCreditXml = new ClassPathResource("META-INF/wlt/queryCredit.xml");
        ClassPathResource consumeCreditXml = new ClassPathResource("META-INF/wlt/consumeCredit.xml");
        ClassPathResource cancelConsumeCreditXml = new ClassPathResource(
            "META-INF/wlt/cancelConsumeCredit.xml");
        ClassPathResource queryConsumeCreditXml = new ClassPathResource(
                "META-INF/wlt/queryConsumeCredit.xml");
        ClassPathResource createTempAccountXml = new ClassPathResource(
            "META-INF/wlt/createTempAccount.xml");
        try {
            addCreditDoc = reader.read(addCreditXml.getInputStream());
            queryCreditDoc = reader.read(queryCreditXml.getInputStream());
            consumeCreditDoc = reader.read(consumeCreditXml.getInputStream());
            cancelConsumeCreditDoc = reader.read(cancelConsumeCreditXml.getInputStream());
            queryConsumeCreditDoc = reader.read(queryConsumeCreditXml.getInputStream());
            createTempAccountDoc = reader.read(createTempAccountXml.getInputStream());
        } catch (DocumentException e) {
            log.error("creditService xml format error!", e);
        } catch (IOException e) {
            log.error("creditService error read xml file!", e);
        }
    }

    /**
     * 万里通积分增加
     * @param memberId 万里通用户ID
     * @param credit 增加积分值
     * @param actionId 操作ID
     */
    public void syncWltCredit(String memberId, int credit, String actionId) {
        Node siebelMessage = addCreditDoc.selectSingleNode(SIEBEL_MESSAGE_XPATH);
        siebelMessage.selectSingleNode("id_member").setText(memberId);
        siebelMessage.selectSingleNode("amount").setText(Integer.toString(credit));
        siebelMessage.selectSingleNode("flow_id").setText(actionId);
        Document response = wltHttpsChannel.call(addUrl, addCreditDoc.asXML());
        Node dataNode = response.selectSingleNode(ADD_RESPONSE_DATA_XPATH);
        if (dataNode == null) {
            throw new CreditServiceException("reponse format error!response:" + response.asXML());
        }

        String returnCode = dataNode.valueOf("returnCode");
        if (!"00".equals(returnCode)) {
            throw new CreditServiceException(returnCode + "|" + dataNode.valueOf("returnMessage"));
        }

    }

    /**
     * 积分查询
     * @param memberId 万里通帐户ID
     * @return 积分余额
     */
    public int queryWltCredit(String memberId) {
        queryCreditDoc.selectSingleNode(MEMBERID_XPATH).setText(memberId);
        Document response = wltHttpsChannel.call(queryUrl, queryCreditDoc.asXML());
        Node returnDataNode = response.selectSingleNode(QUERY_RESPONSE_DATA_XPATH);
        if (returnDataNode == null) {
            throw new CreditServiceException("reponse format error!response:" + response.asXML());
        }
        String errorCode = returnDataNode.valueOf("ErrorCode");
        if ("00".equals(errorCode)) {
            Node pointsLeft = returnDataNode.selectSingleNode("PointsLeft");
            if (pointsLeft != null) {
                return Integer.valueOf(pointsLeft.getText());
            }
            throw new CreditServiceException("reponse hasn't PointsLeft node!");
        } else {
            throw new CreditServiceException(errorCode + "|"
                                             + returnDataNode.valueOf("ErrorMessage"));
        }

    }

    /**
     * 积分消费
     * @param memberId 万里通帐户ID
     * @param credit  积分值
     * @param actionId 操作ID/交易ID
     * @param actionCode 操作类型
     * @return 积分余额
     */
    public int consumeCredit(String memberId, int credit, String actionId, String actionCode) {
        Node siebelMessage = consumeCreditDoc.selectSingleNode(SIEBEL_MESSAGE_XPATH);
        siebelMessage.selectSingleNode("MemberID").setText(memberId);
        siebelMessage.selectSingleNode("Amount").setText(
            (new BigDecimal(credit)).divide(new BigDecimal(500)).toString());
        siebelMessage.selectSingleNode("TTNumber").setText(actionId);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        siebelMessage.selectSingleNode("TTTime").setText(sdf.format(new Date()));
        Document response = wltHttpsChannel.call(consumeUrl, consumeCreditDoc.asXML());
        Node returnDataNode = response.selectSingleNode(CONSUME_RESPONSE_DATA_XPATH);
        if (returnDataNode == null) {
            log.error("consumeCredit.reponse format error!response:" + response.asXML());
            throw new CreditServiceException("reponse format error!response:" + response.asXML());
        }

        String errorCode = returnDataNode.valueOf("ErrorCode");
        if ("00".equals(errorCode)) {
            Node pointsLeft = returnDataNode.selectSingleNode("PointsLeft");
            if (pointsLeft != null) {
                return Integer.valueOf(pointsLeft.getText());
            }
            throw new CreditServiceException("reponse hasn't PointsLeft node!");
        } else if ("04".equals(errorCode)) {
            //积分余额不足
            throw new CreditServiceException(CreditErrorEnum.CREDIT_REMAINING_ERROR) ;
        }
        else {
            throw new CreditServiceException(errorCode + "|"
                                             + returnDataNode.valueOf("ErrorMessage"));
        }
    }

    /**
     * 积分消费查询
     * @param actionId 操作ID/交易ID
     * @return 积分余额
     */
    public boolean queryConsumeCredit(String actionId) {
        Node siebelMessage = queryConsumeCreditDoc.selectSingleNode(SIEBEL_MESSAGE_XPATH);
        siebelMessage.selectSingleNode("TTNumber").setText(actionId);
        Document response = wltHttpsChannel.call(queryConsumeUrl, queryConsumeCreditDoc.asXML());
        Node returnDataNode = response.selectSingleNode(QUERY_RESPONSE_DATA_XPATH);
        if (returnDataNode == null) {
            throw new CreditServiceException("reponse format error!response:" + response.asXML());
        }
        String errorCode = returnDataNode.valueOf("ErrorCode");
        if ("00".equals(errorCode)) {
            return true;
        } else if ("96".equals(errorCode)) {
            return false;
        } else {
            throw new CreditServiceException(errorCode + "|"
                                             + returnDataNode.valueOf("ErrorMessage"));
        }
    }

    /**
     * 消费撤消
     * @param memberId 万里通帐户ID
     * @param credit 原消费金额
     * @param cancelCredit 退货金额
     * @param cancelTTNumber 原单号
     * @param actionId 操作单号
     * @return 积分余额
     */
    public int cancelConsumeCredit(String memberId, int credit, int cancelCredit,
                                   String cancelTTNumber, String actionId) {
        Node siebelMessage = cancelConsumeCreditDoc.selectSingleNode(SIEBEL_MESSAGE_XPATH);
        siebelMessage.selectSingleNode("MemberID").setText(memberId);
        siebelMessage.selectSingleNode("Amount").setText(
            (new BigDecimal(credit)).divide(new BigDecimal(500)).toString());
        siebelMessage.selectSingleNode("CancelAmount").setText(
            (new BigDecimal(cancelCredit)).divide(new BigDecimal(500)).toString());
        siebelMessage.selectSingleNode("CTNumber").setText(cancelTTNumber);
        siebelMessage.selectSingleNode("TTNumber").setText(actionId);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        siebelMessage.selectSingleNode("TTTime").setText(sdf.format(new Date()));
        Document response = wltHttpsChannel.call(cancelConsumeUrl, cancelConsumeCreditDoc.asXML());
        Node returnDataNode = response.selectSingleNode(CONSUME_RESPONSE_DATA_XPATH);
        if (returnDataNode == null) {
            throw new CreditServiceException("reponse format error!response:" + response.asXML());
        }

        String errorCode = returnDataNode.valueOf("ErrorCode");
        if ("00".equals(errorCode)) {
            Node pointsLeft = returnDataNode.selectSingleNode("PointsLeft");
            if (pointsLeft != null) {
                return Integer.valueOf(pointsLeft.getText());
            }
            throw new CreditServiceException("reponse hasn't PointsLeft node!");
        } else {
            throw new CreditServiceException(errorCode + "|"
                                             + returnDataNode.valueOf("ErrorMessage"));
        }
    }

    /**
     * 创建临时账户
     * @param userId 健康通卡ID
     * @param actionId 操作流水号
     * @return 临时账户ID
     */
    public String createTempAccount(String userId, String actionId){
        Node siebelMessage = createTempAccountDoc.selectSingleNode(SIEBEL_MESSAGE_XPATH);
        siebelMessage.selectSingleNode("partnerMemberId").setText(userId);
        siebelMessage.selectSingleNode("serialNumber").setText(actionId);
        
        Document response = wltHttpsChannel.call(createTempAccountUrl, createTempAccountDoc.asXML());
        Node dataNode = response.selectSingleNode(CREATE_TEMP_ACCOUNT);
        if (dataNode == null) {
            throw new CreditServiceException("reponse format error!response:" + response.asXML());
        }
        
        String returnCode = dataNode.valueOf("returnCode");
        if ("00".equals(returnCode)) {
            return dataNode.valueOf("memberId");
        } else {
            throw new CreditServiceException(returnCode + "|" + dataNode.valueOf("returnMessage"));
        }
    }
    
    public void setQueryUrl(String queryUrl) {
        this.queryUrl = queryUrl;
    }

    public void setAddUrl(String addUrl) {
        this.addUrl = addUrl;
    }

    public void setConsumeUrl(String consumeUrl) {
        this.consumeUrl = consumeUrl;
    }

    public void setCancelConsumeUrl(String cancelConsumeUrl) {
        this.cancelConsumeUrl = cancelConsumeUrl;
    }
    
    public void setQueryConsumeUrl(String queryConsumeUrl) {
        this.queryConsumeUrl = queryConsumeUrl;
    }

    public void setCreateTempAccountUrl(String createTempAccountUrl) {
        this.createTempAccountUrl = createTempAccountUrl;
    }
    
}
